iT邦幫忙

2025 iThome 鐵人賽

DAY 19
1
Rust

Bevy Rogue-lite 勇者冒險篇 × Rust 遊戲開發筆記系列 第 19

角色成長與經驗系統

  • 分享至 

  • xImage
  •  

本來沒有想要做角色升級的機制,但看到圖片素材中角色有分成不同裝備,就覺得應該很有趣,可以來做做看。所以這篇就是要把專案中的角色成長系統搭建起來。

預設玩家角色會從 Lv0 開始,透過擊敗敵人累積經驗值,升級時自動更新基礎攻、防以及角色圖案,而 HUD 也能即時顯示等級進度。

預計達成的目標:

  • 建立玩家等級資料模型,集中定義每階段的經驗門檻、基礎攻防與對應角色素材。
  • 讓玩家出生時從 Lv0 + Lv1 武器出發,並記錄後續升級狀態。
  • 敵人死亡時給予對應的 EXP,升級時自動換裝並在 log 中回報。
  • HUD 顯示等級與經驗條,方便觀察整體節奏。

PlayerProgression 與等級常數

四個等級角色素材

四個等級角色素材

新增的 new_demo/src/components/progression.rs 定義 PlayerProgression component,專門儲存玩家等級與累積經驗,並提供查詢基礎數值的 helper:

#[derive(Component, Debug, Clone)]
pub struct PlayerProgression {
    pub level: usize,
    pub experience: u32,
}

impl PlayerProgression {
    pub fn new() -> Self { Self { level: 0, experience: 0 } }
    pub fn next_level_requirement(&self) -> Option<u32> {
        PLAYER_LEVEL_XP_REQUIREMENTS.get(self.level).copied()
    }
    pub fn base_attack(&self) -> i32 {
        PLAYER_LEVEL_BASE_ATTACK
            .get(self.level)
            .copied()
            .unwrap_or_else(|| *PLAYER_LEVEL_BASE_ATTACK.last().unwrap())
    }
    pub fn sprite_path(&self) -> &'static str {
        PLAYER_LEVEL_SPRITE_PATHS
            .get(self.level)
            .copied()
            .unwrap_or_else(|| *PLAYER_LEVEL_SPRITE_PATHS.last().unwrap())
    }
}

相關常數集中在 new_demo/src/constants.rs

pub const PLAYER_MAX_LEVEL: usize = 3;
pub const PLAYER_LEVEL_XP_REQUIREMENTS: [u32; PLAYER_MAX_LEVEL] = [120, 240, 420];
pub const PLAYER_LEVEL_BASE_ATTACK: [i32; PLAYER_MAX_LEVEL + 1] = [15, 24, 34, 46];
pub const PLAYER_LEVEL_BASE_DEFENSE: [i32; PLAYER_MAX_LEVEL + 1] = [4, 7, 11, 16];
pub const PLAYER_LEVEL_SPRITE_PATHS: [&str; PLAYER_MAX_LEVEL + 1] = [
    "characters/players/knight_lv0.png",
    "characters/players/knight_lv1.png",
    "characters/players/knight_lv2.png",
    "characters/players/knight_lv3.png",
];

這樣之後調整等級曲線時,只需要修改常數就可以同步影響所有系統。


Lv0 開場 + Lv1 武器

new_demo/src/systems/setup.rs 把 progression 掛在玩家身上,一出場時就依照 Lv0 的設定初始化攻、防與角色圖案:

let progression = PlayerProgression::new();
commands
    .spawn((
        Player,
        Sprite::from_image(asset_server.load(progression.sprite_path())),
        Health::new(PLAYER_INITIAL_HEALTH),
        Attack::new(progression.base_attack()),
        Defense::new(progression.base_defense()),
        Stamina::new(PLAYER_MAX_STAMINA, PLAYER_STAMINA_REGEN_PER_SECOND),
        EquippedWeapon::new(WeaponKind::Level1),
        progression,
    ));

等級 0 角色開局

這代表角色會以 knight_lv0.png 亮相,之後升級時則由 progression 決定下一張圖。


敵人掉落經驗與 ProgressionPlugin

在敵人淡出前的 despawn_dead_enemies_system 中,新增 EnemyDefeatedEvent 記錄來源與獲得的經驗值 (new_demo/src/systems/enemy.rs):

if experience_reward > 0 {
    defeated_events.write(EnemyDefeatedEvent {
        experience: experience_reward,
        enemy_name: enemy_label,
    });
    info!("擊敗{}獲得 {} EXP", enemy_label, experience_reward);
}

目前預設:史萊姆 30、獨眼巨人 90、寶箱怪 110。後續要調整節奏時,直接改 constants.rs 即可。

為集中成長邏輯,建立 ProgressionPlugin (new_demo/src/plugins/progression.rs) 並在 main.rs 內掛上:

App::new()
    .add_plugins((
        WorldPlugin,
        PlayerPlugin,
        UiPlugin,
        EnemyPlugin,
        ProgressionPlugin,
        // ...
    ))

插件註冊兩個核心系統 (new_demo/src/systems/progression.rs):

  1. apply_enemy_experience_rewards:累加經驗值、處理可能跨越多級的升級,並發送 PlayerLevelUpEvent
  2. apply_player_level_up_effects:收到升級事件後更新 Attack/Defense 基礎值與角色 sprite。
attack.base = progression.base_attack();
defense.base = progression.base_defense();
sprite.image = asset_server.load(progression.sprite_path());
info!(
    "玩家等級提升至 Lv.{}!基礎攻擊 {},基礎防禦 {}",
    level, attack.base, defense.base,
);

系統排程在敵人淡出之後執行,確保擊倒敵人後 HUD 與 Console 立即反映最新狀態。如果玩家已達 Lv3,則會在 log 中提示經驗值不再累積。


HUD 等級資訊

為了讓成長資訊更直觀,update_player_stats_panel (new_demo/src/systems/player_stats.rs) 新增等級與經驗行,並調整面板高度:

let level_line = if let Some(requirement) = progression.next_level_requirement() {
    format!(
        "LV   {:>2}  EXP {:>4}/{:>4}",
        progression.level,
        progression.experience,
        requirement,
    )
} else {
    format!("LV   {:>2}  EXP MAX", progression.level)
};

角色升級資訊

畫面左上角除了原本的攻防/耐力資訊,現在還能看到等級進度條數字。配合 Console log,可以很清楚地確認升級節奏是否符合預期。


小結與下一步

  • 現在有完整的等級體系,從 Lv0 開局逐步解鎖 Lv1~Lv3 的外觀與基礎能力。
  • 敵人死亡事件會提供不同的經驗值,升級流程由獨立的 ProgressionPlugin 負責,後續擴充更容易。
  • HUD 立即顯示等級資訊,方便測試與平衡。

接下來考慮加上的功能:

  1. 加入升級特效/音效,讓升級瞬間更有儀式感。
  2. 其他角色的升級系統。

今日程式碼同步至 repo


上一篇
武器升級系統
下一篇
事件驅動的音效系統
系列文
Bevy Rogue-lite 勇者冒險篇 × Rust 遊戲開發筆記24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言